<?php
use Workerman\Worker;
use Workerman\WebServer;
use Workerman\Lib\Timer;
use PHPSocketIO\SocketIO;
include __DIR__ . '/vendor/autoload.php';

// 全局数组保存uid在线数据
$uidConnectionMap = array();
// 全局数组保存客服在线数据
$kefuConnectionMap = array();
// 记录客服接待人数
$kefu_re_count = array();
// 统计未回复的消息
$wait_re_count = array();
// 离线用户列表
$user_online_list = array();
// 记录最后一次广播的在线用户数
$last_online_count = 0;
// 记录最后一次广播的在线页面数
$last_online_page_count = 0;

// PHPSocketIO服务
$sender_io = new SocketIO(2120);
// 客户端发起连接事件时，设置连接socket的各种事件回调
$sender_io->on('connection', function($socket){
    // 当客户端发来登录事件时触发
    $socket->on('login', function ($uid)use($socket){
        global $uidConnectionMap,$kefuConnectionMap,$last_online_count, $last_online_page_count,$kefu_re_count,$kefu_id;
        // 已经登录过了
        if(isset($socket->uid)){
            return;
        }
        // 更新对应uid的在线数据
        $uid = (string)$uid;

        if(strpos($uid,'kefu')>-1){
            if(!isset($kefuConnectionMap[$uid]))
            {
                $kefuConnectionMap[$uid] = 0;
                
            }
            // 这个uid有++$uidConnectionMap[$uid]个socket连接
            ++$kefuConnectionMap[$uid];
            if(!isset($kefu_re_count[$uid]))
            {
                $kefu_re_count[$uid] = 0; 
            }
            $socket->emit('fp_kefu', $uid);
        }
       
        if(!isset($uidConnectionMap[$uid]))
        {
            $uidConnectionMap[$uid] = 0;
        }
        ++$uidConnectionMap[$uid];
        
        // 将这个连接加入到uid分组，方便针对uid推送数据
        $socket->join($uid);
        $socket->join('online_users');
        $socket->uid = $uid;


        //分配客服
            if(count($kefuConnectionMap)>0&&strpos($uid,'kefu')===false){
                if(count($kefu_re_count)>0){
                    $kefu_id=array_search(min($kefu_re_count), $kefu_re_count);
                    ++$kefu_re_count[$kefu_id];
        
                }else{
                    $keyarr=array_keys($kefuConnectionMap);
                    $kefu_id=$keyarr[rand(0,count($keyarr))];
                    
                }
                $socket->emit('fp_kefu', $kefu_id);
     
            }elseif(count($kefuConnectionMap)==0&&strpos($uid,'kefu')===false){
                $kefu_id='';
                $socket->emit('fp_kefu', $kefu_id);
     
               //return $http_connection->send(json_encode(['status'=>'no_kefu_noline'])); 
            }elseif(count($kefuConnectionMap)==1&&strpos($uid,'kefu')>-1){
                $socket->to('online_users')->emit('fp_kefu', $uid);

            }  
        
    });
    
    // 当客户端断开连接是触发（一般是关闭网页或者跳转刷新导致）
    $socket->on('disconnect', function () use($socket) {
        if(!isset($socket->uid))
        {
             return;
        }
        global $uidConnectionMap, $sender_io,$kefu_re_count,$kefuConnectionMap;
        // 将uid的在线socket数减一
        if(--$uidConnectionMap[$socket->uid] <= 0)
        {
            unset($uidConnectionMap[$socket->uid]);

        }
        
         if(isset($kefuConnectionMap[$socket->uid]))
        {
            if(--$kefuConnectionMap[$socket->uid] <= 0)
            {
                unset($kefuConnectionMap[$socket->uid]);
            }

        }
         if(isset($kefu_re_count[$socket->uid]))
        {
             unset($kefu_re_count[$socket->uid]);
        }
        $socket->leave('online_users');
   
    });
});

// 当$sender_io启动后监听一个http端口，通过这个端口可以给任意uid或者所有uid推送数据
$sender_io->on('workerStart', function(){
    // 监听一个http端口
    $inner_http_worker = new Worker('http://0.0.0.0:2121');
    // 当http客户端发来数据时触发
    $inner_http_worker->onMessage = function($http_connection, $data){
        global $uidConnectionMap,$kefuConnectionMap,$kefu_re_count,$wait_re_count,$kefu_id;
        $_POST = $_POST ? $_POST : $_GET;
        // 推送数据的url格式 type=publish&to=uid&content=xxxx
        
        switch(@$_POST['type']){
            case 'publish':
                global $sender_io;
                $to = @$_POST['to'];
                $from = @$_POST['from'];
                $type = @$_POST['msg_type'];
                if($type==1){
                    //如果$to为空，系统自动分配客服
                    if($to==''){
                        $to=$kefu_id;
                        if($to==''){
                            return $http_connection->send(json_encode(['status'=>'no_kefu_noline','to_uid'=>$to]));
                        }
                       
                    }else{
                        if(strpos($to,'kefu')>-1){
                            if(!isset($kefu_re_count[$to]))
                            {
                                $kefu_re_count[$to] = 0;
                            }
                        }   
                    }
                }

                $_POST['content'] = htmlspecialchars(@$_POST['content']);
                $msg['content']=$_POST['content'];
                $msg['from']=$from;
                $msg['nickname']=@$_POST['nickname'];
                $msg['head_pic']=@$_POST['head_pic'];
                $msg['time']=@$_POST['time'];
                // 有指定uid则向uid所在socket组发送数据
                if($to){
                    $sender_io->to($to)->emit('new_msg', json_encode($msg));
                }
                // http接口返回，如果用户离线socket返回fail
                if($to && !isset($uidConnectionMap[$to])){
                    //统计未回复消息数量
                    if(!isset($wait_re_count[$to]))
                    {
                        $wait_re_count[$to] = 0;
                    }
                    ++$wait_re_count[$to];

                    return $http_connection->send(json_encode(['status'=>'offline','to_uid'=>$to]));
                }else{
                    return $http_connection->send(json_encode(['status'=>'ok','to_uid'=>$to]));
                }
        }
        return $http_connection->send(json_encode(['status'=>'fail','to_uid'=>$to]));
    };
    // 执行监听
    $inner_http_worker->listen();


    // 一个定时器，定时向所有uid推送当前uid在线数及在线页面数
    Timer::add(1, function(){
        global $uidConnectionMap, $sender_io, $last_online_count, $last_online_page_count,$kefuConnectionMap,$user_online_list,$off_mes_user,$off_mes_kefu,$wait_re_count;

        //当用户下线时
        if(count($user_online_list)!=count($uidConnectionMap)){
                $off_arr=array_diff_assoc($user_online_list,$uidConnectionMap);
                $online_arr=array_diff_assoc($uidConnectionMap,$user_online_list);
                $off_user=array_keys($off_arr);
                $online_user=array_keys($online_arr);
                if(!empty($off_user)){
                    $sender_io->emit('on_user_offline', json_encode($off_user));
                }
                    
                if(!empty($online_user)){
                    $sender_io->emit('on_user_online', json_encode($online_user));
                    $off_mes_kefu=[];
                    if(count($wait_re_count)>0){
                        $wait_re_arr= array_unique(array_intersect($online_user,array_keys($wait_re_count)));
    
                        foreach ($wait_re_arr as $key => $value) {
                            if(strpos($value,'kefu')>-1){
                                $off_mes_kefu[]= $value;
                            }else{
                                $off_mes_user[]= $value;
                            }
                        }
                        if(!empty($off_mes_user)){
                            $sender_io->emit('off_mes_user', implode(',',$off_mes_user));
                            $wait_re_arr=array_intersect($wait_re_arr,$off_mes_user);
                        }
                       
                    }

                        $sender_io->emit('off_mes_kefu', implode(',',$off_mes_kefu));
                        if(!empty($off_mes_kefu)){
                            $wait_re_arr=array_intersect($wait_re_arr,$off_mes_user);
                        }
                        
                    
                    
                } 
                    
                $user_online_list=$uidConnectionMap;
        
        }
        $online_count_now = count($uidConnectionMap);
        $kefu_count_now = count($kefuConnectionMap);
        $online_page_count_now = array_sum($uidConnectionMap);
        $last_fp=0;
        // 只有在客户端在线数变化了才广播，减少不必要的客户端通讯
        if($last_online_count != $kefu_count_now || $last_online_page_count != $online_page_count_now)
        {
            $sender_io->emit('update_online_count', "当前<b>{$kefu_count_now}</b>客服在线，共打开<b>{$online_page_count_now}</b>个页面");
            //$sender_io->emit('update_kefu_status', $kefu_count_now);

            $last_online_count = $kefu_count_now;
            $last_online_page_count = $online_page_count_now;
        }
       
       
    });
});

if(!defined('GLOBAL_START'))
{
    Worker::runAll();
}

